
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "driver/i2s.h"
#include "driver/gpio.h"
#include "esp_system.h"
#include "esp_log.h"
#include "driver/rmt.h"
#include "led_strip.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "nvs_flash.h"
#include "driver/ledc.h"
#include "driver/timer.h"

#include "esp_wifi.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#include "freertos/event_groups.h"
#include "esp_littlefs.h"
#include <esp_http_server.h>
#include "cJSON.h"
#include "mqtt_client.h"
#include "esp_rom_tjpgd.h"

// #include "esp_spiffs.h"
// #include "esp_vfs.h"
// #include "esp_vfs_fat.h"


#define SAMPLE_RATE     (44100)
#define I2S_NUM         (0)
#define WAVE_FREQ_HZ    (100)
#define PI              (3.14159265)
#define I2S_BCK_IO      (GPIO_NUM_48)
#define I2S_WS_IO       (GPIO_NUM_45)
#define I2S_DO_IO       (GPIO_NUM_47)
#define I2S_DI_IO       (-1)


#define TIMER_DIVIDER         (2)  //  Hardware timer clock divider
#define TIMER_SCALE           ((8*10)/(TIMER_DIVIDER))  // convert counter value to seconds

#define STEP_EN     GPIO_NUM_3
#define STEP_PUL    GPIO_NUM_5
#define STEP_DIR    GPIO_NUM_4
#define STEP_SPRD   GPIO_NUM_8
#define STEP_PWM    GPIO_NUM_46
#define STEP_MS1    GPIO_NUM_16
#define STEP_MS2    GPIO_NUM_15
#define STEP_INDEX  GPIO_NUM_6
#define STEP_DIAG  GPIO_NUM_7
#define STEP_KEY   GPIO_NUM_0

#define LEDC_TIMER              LEDC_TIMER_0
#define LEDC_MODE               LEDC_LOW_SPEED_MODE
#define LEDC_OUTPUT_IO          STEP_PWM // Define the output GPIO
#define LEDC_CHANNEL            LEDC_CHANNEL_1
#define LEDC_DUTY_RES           LEDC_TIMER_10_BIT // Set duty resolution to 13 bits
#define LEDC_DUTY               (100) // Set duty to 50%. ((2 ** 13) - 1) * 50% = 4095
#define LEDC_FREQUENCY          (20000) // Frequency in Hertz. Set frequency at 5 kHz

#define SAMPLE_PER_CYCLE (SAMPLE_RATE/WAVE_FREQ_HZ)

#define IMAGE_W 336
#define IMAGE_H 256

extern const uint8_t lr_wav_start[] asm("_binary_123_wav_start");
extern const uint8_t lr_wav_end[]   asm("_binary_123_wav_end");

/* FreeRTOS event group to signal when we are connected*/
static EventGroupHandle_t s_wifi_event_group;

/* The event group allows multiple bits for each event, but we only care about two events:
 * - we are connected to the AP with an IP
 * - we failed to connect after the maximum amount of retries */
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT      BIT1

static const char *TAG = "wifi station";

static int s_retry_num = 0;

esp_mqtt_client_handle_t matt_client;
char mqtt_light[30];
char mqtt_open_btm[30];
char mqtt_last_pic_btm[30];
char mqtt_next_pic_btm[30];
char mqtt_del_pic_btm[30];
char mqtt_pic_btm[30];
char mqtt_video_btm[30];
char mqtt_image_esp[30];
char mqtt_image_phone[30];
char image_data[20000];
char is_open = 0;
int page_num = 1;
int is_page_change = 0;
char is_video = 1;
int video_page = 0;
static SemaphoreHandle_t ctrl_task_sem;

led_strip_t *strip1;
led_strip_t *strip2;
led_strip_t *strip3;
led_strip_t *strip4;

uint8_t *ledData; 
uint8_t *ledDatas; 
uint8_t *music_data; 
size_t music_Size;
//Data that is passed from the decoder function to the infunc/outfunc functions.
typedef struct {
    // const unsigned char *inData; //Pointer to jpeg data
    // uint16_t inPos;              //Current position in jpeg data
    FILE *fp;
    uint8_t *outData;          //Array of IMAGE_H pointers to arrays of IMAGE_W 16-bit pixel values
    int outW;                    //Width of the resulting file
    int outH;                    //Height of the resulting file
} JpegDev;

JpegDev jd;

esp_vfs_littlefs_conf_t littlefs_conf = {
    .base_path = "/littlefs",
    .partition_label = "littlefs",
    .format_if_mount_failed = true,
    .dont_mount = false,
};


typedef struct {
    int timer_group;
    int timer_idx;
    int alarm_interval;
    bool auto_reload;
} example_timer_info_t;

typedef struct {
    example_timer_info_t info;
    uint64_t timer_counter_value;
} example_timer_event_t;


uint32_t num = 0;
uint32_t num1 = 0;
uint16_t r,g,b;
int a_p = 0;
uint16_t speed = 100;
float speed1 = 100;

static httpd_handle_t start_webserver(void);
static void mqtt_app_start(void);

static bool IRAM_ATTR timer_group_isr_callback(void *args)
{
    BaseType_t high_task_awoken = pdFALSE;
    // gpio_set_level(STEP_PUL, 0);
    
    GPIO.out_w1tc = (1 << STEP_PUL);
    num++;

    if(num%speed==0)
    {
        num1++;
        GPIO.out_w1ts = (1 << STEP_PUL);
        // gpio_set_level(STEP_PUL, 1);
        if(num1%8==0)
        {
            a_p+=1;
            if(a_p>=200)a_p=0;
            xSemaphoreGive(ctrl_task_sem);

        }
    }



    return high_task_awoken == pdTRUE; // return whether we need to yield at the end of ISR

}

int connect_num = 0;
int is_connected = 0;

esp_err_t my_event_handler(void *ctx, system_event_t *event)
{
    switch (event->event_id)
    {
    case SYSTEM_EVENT_STA_START:
        
        ESP_LOGI(TAG, "Connecting to AP...");
        esp_wifi_connect();
        break;

    case SYSTEM_EVENT_STA_GOT_IP:

        start_webserver();
        mqtt_app_start();
        is_connected = 1;
        ESP_LOGI(TAG, "Connected.");
        break;

    case SYSTEM_EVENT_STA_DISCONNECTED:
        vTaskDelay(3000 / portTICK_RATE_MS);
        connect_num++;
        if(connect_num<5||is_connected)
        {
            ESP_LOGI(TAG, "Wifi disconnected, try to connect ...");
            esp_wifi_connect();            
        }else
        {
            ESP_LOGI(TAG, "Wifi open AP");
            ESP_ERROR_CHECK(esp_wifi_stop());
            // wifi_init_softap();
        }

        break;

    default:
        break;
    }
    
    return ESP_OK;
}

void my_wifi_init(void)
{
    tcpip_adapter_init();
    ESP_ERROR_CHECK( esp_event_loop_init(my_event_handler, NULL) );
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
    ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
    wifi_config_t sta_config = {
        .sta = {
            .ssid = "wifi",
            .password = "12345678",
            .listen_interval = 3,
            .bssid_set = false
        }
    };

    ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &sta_config) );
    ESP_ERROR_CHECK( esp_wifi_start() );
}




static void wifi_event_handler(void* arg, esp_event_base_t event_base,
                                    int32_t event_id, void* event_data)
{
    if (event_id == WIFI_EVENT_AP_STACONNECTED) {
        wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data;
        ESP_LOGI(TAG, "station "MACSTR" join, AID=%d",
                 MAC2STR(event->mac), event->aid);
    } else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) {
        wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data;
        ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d",
                 MAC2STR(event->mac), event->aid);
    }
}

static void step_gpio_init(void)
{
    //zero-initialize the config structure.
    gpio_config_t out_conf = {};
    //disable interrupt
    out_conf.intr_type = GPIO_INTR_DISABLE;
    //set as output mode
    out_conf.mode = GPIO_MODE_OUTPUT;
    //bit mask of the pins that you want to set,e.g.GPIO18/19
    out_conf.pin_bit_mask =
    		((1ULL<<STEP_MS1)|(1ULL<<STEP_EN)|(1ULL<<STEP_PUL)|(1ULL<<STEP_DIR)|
            (1ULL<<STEP_MS1)|(1ULL<<STEP_SPRD) );
    //disable pull-down mode
    out_conf.pull_down_en = 1;
    //disable pull-up mode
    out_conf.pull_up_en = 1;
    //configure GPIO with the given settings
    gpio_config(&out_conf);

    //zero-initialize the config structure.
    gpio_config_t in_conf = {};
    //disable interrupt
    in_conf.intr_type = GPIO_INTR_DISABLE;
    //set as output mode
    in_conf.mode = GPIO_MODE_INPUT;
    //bit mask of the pins that you want to set,e.g.GPIO18/19
    in_conf.pin_bit_mask =
    	((1ULL<<STEP_KEY)|(1ULL<<STEP_DIAG)|(1ULL<<STEP_INDEX));
    //disable pull-down mode
    in_conf.pull_down_en = 0;
    //disable pull-up mode
    in_conf.pull_up_en = 1;
    //configure GPIO with the given settings
    gpio_config(&in_conf);


}


static void pwm_init(void)
{
    // Prepare and then apply the LEDC PWM timer configuration
    ledc_timer_config_t ledc_timer = {
        .speed_mode       = LEDC_MODE,
        .timer_num        = LEDC_TIMER,
        .duty_resolution  = LEDC_DUTY_RES,
        .freq_hz          = LEDC_FREQUENCY,  // Set output frequency at 5 kHz
        .clk_cfg          = LEDC_AUTO_CLK
    };
    ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));

    // Prepare and then apply the LEDC PWM channel configuration
    ledc_channel_config_t ledc_channel = {
        .speed_mode     = LEDC_MODE,
        .channel        = LEDC_CHANNEL,
        .timer_sel      = LEDC_TIMER,
        .intr_type      = LEDC_INTR_DISABLE,
        .gpio_num       = LEDC_OUTPUT_IO,
        .duty           = 0, // Set duty to 0%
        .hpoint         = 0
    };
    ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
}

static void example_tg_timer_init(int group, int timer, bool auto_reload, int timer_interval_sec)
{
    /* Select and initialize basic parameters of the timer */
    timer_config_t config = {
        .divider = TIMER_DIVIDER,
        .counter_dir = TIMER_COUNT_UP,
        .counter_en = TIMER_PAUSE,
        .alarm_en = TIMER_ALARM_EN,
        .auto_reload = auto_reload,
    }; // default clock source is APB
    timer_init(group, timer, &config);

    /* Timer's counter will initially start from value below.
       Also, if auto_reload is set, this value will be automatically reload on alarm */
    timer_set_counter_value(group, timer, 0);

    /* Configure the alarm value and the interrupt on alarm. */
    timer_set_alarm_value(group, timer, timer_interval_sec * TIMER_SCALE);
    timer_enable_intr(group, timer);

    example_timer_info_t *timer_info = calloc(1, sizeof(example_timer_info_t));
    timer_info->timer_group = group;
    timer_info->timer_idx = timer;
    timer_info->auto_reload = auto_reload;
    timer_info->alarm_interval = timer_interval_sec;
    timer_isr_callback_add(group, timer, timer_group_isr_callback, timer_info, ESP_INTR_FLAG_IRAM);

    timer_start(group, timer);
}



static esp_err_t hello_get_handler(httpd_req_t *req)
{
    char*  buf;
    size_t buf_len;

    /* Get header value string length and allocate memory for length + 1,
     * extra byte for null termination */
    buf_len = httpd_req_get_hdr_value_len(req, "Host") + 1;
    if (buf_len > 1) {
        buf = malloc(buf_len);
        /* Copy null terminated value string into buffer */
        if (httpd_req_get_hdr_value_str(req, "Host", buf, buf_len) == ESP_OK) {
//            ESP_LOGI(TAG, "Found header => Host: %s", buf);
        }
        free(buf);
    }

    buf_len = httpd_req_get_hdr_value_len(req, "Test-Header-2") + 1;
    if (buf_len > 1) {
        buf = malloc(buf_len);
        if (httpd_req_get_hdr_value_str(req, "Test-Header-2", buf, buf_len) == ESP_OK) {
//            ESP_LOGI(TAG, "Found header => Test-Header-2: %s", buf);
        }
        free(buf);
    }

    buf_len = httpd_req_get_hdr_value_len(req, "Test-Header-1") + 1;
    if (buf_len > 1) {
        buf = malloc(buf_len);
        if (httpd_req_get_hdr_value_str(req, "Test-Header-1", buf, buf_len) == ESP_OK) {
//            ESP_LOGI(TAG, "Found header => Test-Header-1: %s", buf);
        }
        free(buf);
    }

    /* Read URL query string length and allocate memory for length + 1,
     * extra byte for null termination */
    buf_len = httpd_req_get_url_query_len(req) + 1;
    if (buf_len > 1) {
        buf = malloc(buf_len);
        if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) {
//            ESP_LOGI(TAG, "Found URL query => %s", buf);
            char param[32];
            /* Get value of expected key from query string */
            if (httpd_query_key_value(buf, "query1", param, sizeof(param)) == ESP_OK) {
//                ESP_LOGI(TAG, "Found URL query parameter => query1=%s", param);
            }
            if (httpd_query_key_value(buf, "query3", param, sizeof(param)) == ESP_OK) {
//                ESP_LOGI(TAG, "Found URL query parameter => query3=%s", param);
            }
            if (httpd_query_key_value(buf, "query2", param, sizeof(param)) == ESP_OK) {
//                ESP_LOGI(TAG, "Found URL query parameter => query2=%s", param);
            }
        }
        free(buf);
    }

    /* Set some custom headers */
    httpd_resp_set_hdr(req, "Custom-Header-1", "Custom-Value-1");
    httpd_resp_set_hdr(req, "Custom-Header-2", "Custom-Value-2");

    /* Send response with custom headers and body set as the
     * string passed in user context*/
    const char* resp_str = (const char*) req->user_ctx;
    httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN);

    /* After sending the HTTP response the old HTTP request
     * headers are lost. Check if HTTP request headers can be read now. */
    if (httpd_req_get_hdr_value_len(req, "Host") == 0) {
//        ESP_LOGI(TAG, "Request headers lost");
    }
    return ESP_OK;
}

static const httpd_uri_t hello = {
    .uri       = "/hello",
    .method    = HTTP_GET,
    .handler   = hello_get_handler,
    /* Let's pass response string in user
     * context to demonstrate it's usage */
    .user_ctx  = "Hello World!"
};




static esp_err_t state_get_handler(httpd_req_t *req)
{
    httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
    httpd_resp_set_hdr(req, "Content-Type", "application/json; charset=utf-8");
    //const char* resp_str = (const char*) req->user_ctx;
    char send_str[600];
    
    sprintf(send_str,"{\"speed1\":%f}",
    		speed1);
    httpd_resp_send(req, send_str, HTTPD_RESP_USE_STRLEN);
    return ESP_OK;
}

static const httpd_uri_t state = {
    .uri       = "/state",
    .method    = HTTP_GET,
    .handler   = state_get_handler,
    .user_ctx  = "Hello World!"
};

#ifndef myMIN
# define myMIN(a,b) ((a) < (b) ? (a) : (b))
#endif

static esp_err_t control_post_handler(httpd_req_t *req)
{
    char buf[100];
    int ret, remaining = req->content_len;
    // comtrol_time_out = 300;
    
    while (remaining > 0) {

        if ((ret = httpd_req_recv(req, buf,
        		myMIN(remaining, sizeof(buf)))) <= 0)
        {
            if (ret == HTTPD_SOCK_ERR_TIMEOUT) {

                continue;
            }
            return ESP_FAIL;
        }


        httpd_resp_send_chunk(req, buf, ret);
        remaining -= ret;

    }

    cJSON *root = NULL;
	cJSON *node1 = NULL;
	//cJSON *node2 = NULL;
	root = cJSON_Parse(buf);
	if(root)
	{
		node1 = cJSON_GetObjectItem(root, "robot_global_speed");
		if(node1)
		{
			// robot_global_speed = node1->valueint;
            // system_val[150] = robot_global_speed;
		}
		node1 = cJSON_GetObjectItem(root, "robot_key");
		if(node1)
		{
			// robot_key = node1->valueint;
		}
		node1 = cJSON_GetObjectItem(root, "robot_model");
		if(node1)
		{
			// robot_model = node1->valueint;
		}


	}
	cJSON_Delete(root);
	

    // End response
    httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
    httpd_resp_set_hdr(req, "Content-Type", "application/json; charset=utf-8");
    httpd_resp_send_chunk(req, NULL, 0);
    return ESP_OK;
}

static const httpd_uri_t control = {
    .uri       = "/control",
    .method    = HTTP_POST,
    .handler   = control_post_handler,
    .user_ctx  = NULL
};


static esp_err_t echo_post_handler(httpd_req_t *req)
{
    char buf[100];
    int ret, remaining = req->content_len;

    while (remaining > 0) {
        /* Read the data for the request */
        if ((ret = httpd_req_recv(req, buf,
        		myMIN(remaining, sizeof(buf)))) <= 0)
        {
            if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
                /* Retry receiving if timeout occurred */
                continue;
            }
            return ESP_FAIL;
        }

        /* Send back the same data */
        httpd_resp_send_chunk(req, buf, ret);
        remaining -= ret;

        /* Log data received */
//        ESP_LOGI(TAG, "=========== RECEIVED DATA ==========");
//        ESP_LOGI(TAG, "%.*s", ret, buf);
//        ESP_LOGI(TAG, "====================================");
    }

    // End response
    httpd_resp_send_chunk(req, NULL, 0);
    return ESP_OK;
}

static const httpd_uri_t echo = {
    .uri       = "/echo",
    .method    = HTTP_POST,
    .handler   = echo_post_handler,
    .user_ctx  = NULL
};




static esp_err_t readfile_get_handler(httpd_req_t *req)
{
    char*  buf;
    size_t buf_len;
    char send_str[100]={0};
    char file_path[200]={0};   

    httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
    httpd_resp_set_hdr(req, "Content-Type", "text/html; charset=utf-8");
    //const char* resp_str = (const char*) req->user_ctx;
    
    
    buf_len = httpd_req_get_url_query_len(req) + 1;
    if (buf_len > 1) {
        buf = malloc(buf_len);
        if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) {
            char param[180];
            /* Get value of expected key from query string */
            if (httpd_query_key_value(buf, "name", param, sizeof(param)) == ESP_OK) {
                sprintf(file_path,"/littlefs/%s",param);
            }

        }
        free(buf);
    }

    FILE* f = fopen(file_path, "r");
    size_t fileSize;
    while(!feof(f)) 
    {
        fileSize = fread(send_str,sizeof(char),100,f);
        httpd_resp_send_chunk(req, send_str, fileSize);
    }
    // fread(send_str,sizeof(char),300,f);
    
    fclose(f);
    httpd_resp_send_chunk(req, NULL, 0);
    // httpd_resp_send(req, send_str, HTTPD_RESP_USE_STRLEN);
    return ESP_OK;
}

static const httpd_uri_t readfile = {
    .uri       = "/readfile",
    .method    = HTTP_GET,
    .handler   = readfile_get_handler,
    .user_ctx  = "read file"
};



static esp_err_t writefile_post_handler(httpd_req_t *req)
{
    char*  buf;
    size_t buf_len;
    char file_str[200]={0};
    char file_path[200]={0};
    buf_len = httpd_req_get_url_query_len(req) + 1;
    if (buf_len > 1) {
        buf = malloc(buf_len);
        if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) {
            char param[180];
            /* Get value of expected key from query string */
            if (httpd_query_key_value(buf, "name", param, sizeof(param)) == ESP_OK) {
                sprintf(file_path,"/littlefs/%s",param);
            }

        }
        free(buf);
    }

    int ret, remaining = req->content_len;
    FILE* f = fopen(file_path, "w");
    while (remaining > 0) {

        if ((ret = httpd_req_recv(req, file_str,
        		myMIN(remaining, sizeof(file_str)))) <= 0)
        {
            if (ret == HTTPD_SOCK_ERR_TIMEOUT) {

                continue;
            }
            return ESP_FAIL;
        }
        fwrite(file_str,sizeof(char),ret,f);

        // httpd_resp_send_chunk(req, file_str, ret);
        remaining -= ret;

    }

    // fprintf(f, file_str);
    fclose(f);

    // End response
    httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
    httpd_resp_set_hdr(req, "Content-Type", "text/html; charset=utf-8");
    // httpd_resp_send_chunk(req, NULL, 0);
    httpd_resp_send(req, "OK", HTTPD_RESP_USE_STRLEN);
    return ESP_OK;
}

static const httpd_uri_t writefile = {
    .uri       = "/writefile",
    .method    = HTTP_POST,
    .handler   = writefile_post_handler,
    .user_ctx  = NULL
};



static esp_err_t filemsg_get_handler(httpd_req_t *req)
{
     //const char* resp_str = (const char*) req->user_ctx;
    char send_str[300]={0};
    char is_fist = 1;
    // esp_vfs_spiffs_register(&file_conf);
    size_t total = 0, used = 0;
    httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
    httpd_resp_set_hdr(req, "Content-Type", "application/json; charset=utf-8");
    // esp_spiffs_info(file_conf.partition_label, &total, &used);
    esp_littlefs_info(littlefs_conf.partition_label, &total, &used);
    sprintf(send_str,"{\"total\":%d,\"used\":%d,\"name\":[",
            total,used);
    httpd_resp_send_chunk(req, send_str, HTTPD_RESP_USE_STRLEN);
    DIR *pDir = NULL;
    struct dirent *pEnt = NULL;
    pDir = opendir("/littlefs");
    if(pDir !=NULL)
    {
        while(1)
        {
            pEnt = readdir(pDir);
            if(pEnt !=NULL)
            {
                if(is_fist)
                {
                    sprintf(send_str,"\"%s\"",pEnt->d_name);
                    httpd_resp_send_chunk(req, send_str, HTTPD_RESP_USE_STRLEN);
                    is_fist =0;
                }else
                {
                    sprintf(send_str,",\"%s\"",pEnt->d_name);
                    httpd_resp_send_chunk(req, send_str, HTTPD_RESP_USE_STRLEN);
                }
            }else 
            {
                if(is_fist)
                {
                    sprintf(send_str,"\"null\"]}");
                }else
                {
                    sprintf(send_str,"]}");
                }
                httpd_resp_send_chunk(req, send_str, HTTPD_RESP_USE_STRLEN);
                break;
            }

        }
    }
    closedir(pDir);
    httpd_resp_send_chunk(req, NULL, 0);
    return ESP_OK;
}

static const httpd_uri_t filemsg = {
    .uri       = "/filemsg",
    .method    = HTTP_GET,
    .handler   = filemsg_get_handler,
    .user_ctx  = "filemsg"
};



static esp_err_t delfile_get_handler(httpd_req_t *req)
{
    char*  buf;
    size_t buf_len;
    char file_path[200]={0};   

    httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
    httpd_resp_set_hdr(req, "Content-Type", "text/html; charset=utf-8");
    //const char* resp_str = (const char*) req->user_ctx;
    
    buf_len = httpd_req_get_url_query_len(req) + 1;
    if (buf_len > 1) {
        buf = malloc(buf_len);
        if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) {
            char param[180];
            /* Get value of expected key from query string */
            if (httpd_query_key_value(buf, "name", param, sizeof(param)) == ESP_OK) {
                sprintf(file_path,"/littlefs/%s",param);
            }

        }
        free(buf);
    }
    remove(file_path);

    httpd_resp_send(req, "OK", HTTPD_RESP_USE_STRLEN);
    return ESP_OK;
}

static const httpd_uri_t delfile = {
    .uri       = "/delfile",
    .method    = HTTP_GET,
    .handler   = delfile_get_handler,
    .user_ctx  = "delete file"
};




static httpd_handle_t start_webserver(void)
{
    httpd_handle_t server = NULL;
    httpd_config_t config = HTTPD_DEFAULT_CONFIG();
    config.lru_purge_enable = true;
    config.server_port = 8080;
    
    // Start the httpd server
//    ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port);
    if (httpd_start(&server, &config) == ESP_OK) {
        // Set URI handlers
//        ESP_LOGI(TAG, "Registering URI handlers");
        httpd_register_uri_handler(server, &hello);
        httpd_register_uri_handler(server, &state);
        httpd_register_uri_handler(server, &control);
        httpd_register_uri_handler(server, &echo);
        httpd_register_uri_handler(server, &readfile);
        httpd_register_uri_handler(server, &writefile);
        httpd_register_uri_handler(server, &filemsg);
        httpd_register_uri_handler(server, &delfile);


//        httpd_register_uri_handler(server, &ctrl);
        #if CONFIG_EXAMPLE_BASIC_AUTH
        httpd_register_basic_auth(server);
        #endif
        return server;
    }

//    ESP_LOGI(TAG, "Error starting server!");
    return NULL;
}

static void stop_webserver(httpd_handle_t server)
{
    // Stop the httpd server
    httpd_stop(server);
}

static void disconnect_handler(void* arg, esp_event_base_t event_base,
                               int32_t event_id, void* event_data)
{
    httpd_handle_t* server = (httpd_handle_t*) arg;
    if (*server) {
//        ESP_LOGI(TAG, "Stopping webserver");
        stop_webserver(*server);
        *server = NULL;
    }
}

static void connect_handler(void* arg, esp_event_base_t event_base,
                            int32_t event_id, void* event_data)
{
    httpd_handle_t* server = (httpd_handle_t*) arg;
    if (*server == NULL) {
//        ESP_LOGI(TAG, "Starting webserver");
        *server = start_webserver();
    }
}

static uint32_t infunc(esp_rom_tjpgd_dec_t *decoder, uint8_t *buf, uint32_t len)
{
    JpegDev *jd = (JpegDev *)decoder->device;
    // printf("Reading %d bytes\n", len);
    if (buf != NULL) {
        return fread(buf,1,len,jd->fp);
        // memcpy(buf, jd->inData + jd->inPos, len);
    }
    else {
        return fseek(jd->fp,len, SEEK_CUR) ? 0 : len;
    }
    // jd->inPos += len;
    // return len;
}

static uint32_t outfunc(esp_rom_tjpgd_dec_t *decoder, void *bitmap, esp_rom_tjpgd_rect_t *rect)
{
    unsigned char *in = (unsigned char *)bitmap;
    unsigned char *out;
    int y,bws,bwd;
    // printf("Rect %d,%d - %d,%d\n", rect->top, rect->left, rect->bottom, rect->right);
    JpegDev *jd = (JpegDev *)decoder->device;
    out = jd->outData + ((jd->outW * rect->top) + rect->left) * 3;
    bws = 3 * ((rect->right - rect->left) + 1);
    bwd = 3 * jd->outW;
    for (y = rect->top; y <= rect->bottom; y++) {
        memcpy(out, in, bws);
        in +=bws;
        out += bwd;
    }
    return 1;
}



static void led_task(void *arg)
{
    uint32_t pos1 = 0;
    uint32_t pos2 = 0;
    uint32_t pos3 = 0;
    uint32_t pos4 = 0;   
    while (1) {
        xSemaphoreTake(ctrl_task_sem, portMAX_DELAY);
        for (int j = 0; j < 20; j += 1) {
            // Build RGB values
            // hue = j * 360 / CONFIG_EXAMPLE_STRIP_LED_NUMBER + start_rgb;
            // led_strip_hsv2rgb(hue, 100, 100, &red, &green, &blue);
            // Write RGB values to strip driver
            // pos1 = ((int)(-sin(a_p/15.9155)*j+20)*40+(int)(cos(a_p/15.9155)*j)+20);
            // pos2 = ((int)(-sin((a_p+25)/15.9155)*j+20)*40+(int)(cos((a_p+25)/15.9155)*j)+20);
            // pos3 = ((int)(-sin((a_p+50)/15.9155)*j+20)*40+(int)(cos((a_p+50)/15.9155)*j)+20);
            // pos4 = ((int)(-sin((a_p+75)/15.9155)*j+20)*40+(int)(cos((a_p+75)/15.9155)*j)+20);
           
            // printf("[%d,%d]",r,pos);
            // ESP_ERROR_CHECK(strip1->set_pixel(strip1, j, jd.outData[pos1*3]*(j+3)/300, jd.outData[pos1*3+1]*(j+3)/300, jd.outData[pos1*3+2]*(j+3)/300));
            // ESP_ERROR_CHECK(strip2->set_pixel(strip2, j, jd.outData[pos2*3]*(j+3)/300, jd.outData[pos2*3+1]*(j+3)/300, jd.outData[pos2*3+2]*(j+3)/300));
            // ESP_ERROR_CHECK(strip3->set_pixel(strip3, j, jd.outData[pos3*3]*(j+3)/300, jd.outData[pos3*3+1]*(j+3)/300, jd.outData[pos3*3+2]*(j+3)/300));
            // ESP_ERROR_CHECK(strip4->set_pixel(strip4, j, jd.outData[pos4*3]*(j+3)/300, jd.outData[pos4*3+1]*(j+3)/300, jd.outData[pos4*3+2]*(j+3)/300));
            // if(a_p==0)ESP_ERROR_CHECK(strip1->set_pixel(strip1, j, 2,2,2));
            // else ESP_ERROR_CHECK(strip1->set_pixel(strip1, j, 0,0,0));
            // if(a_p==100)ESP_ERROR_CHECK(strip2->set_pixel(strip2, j, 2,2,2));
            // else ESP_ERROR_CHECK(strip2->set_pixel(strip2, j, 0,0,0));
            // if(a_p==150)ESP_ERROR_CHECK(strip3->set_pixel(strip3, j, 2,2,2));
            // else ESP_ERROR_CHECK(strip3->set_pixel(strip3, j, 0,0,0));
            // if(a_p==50)ESP_ERROR_CHECK(strip4->set_pixel(strip4, j, 2,2,2));
            // else ESP_ERROR_CHECK(strip4->set_pixel(strip4, j, 0,0,0));
            ESP_ERROR_CHECK(strip1->set_pixel(strip1, j, ledData[a_p*240+j*12],ledData[a_p*240+j*12+1],ledData[a_p*240+j*12+2]));
            ESP_ERROR_CHECK(strip2->set_pixel(strip2, j, ledData[((a_p+100)%200)*240+j*12+3],ledData[((a_p+100)%200)*240+j*12+4],ledData[((a_p+100)%200)*240+j*12+5]));
            ESP_ERROR_CHECK(strip3->set_pixel(strip3, j, ledData[((a_p+150)%200)*240+j*12+6],ledData[((a_p+150)%200)*240+j*12+7],ledData[((a_p+150)%200)*240+j*12+8]));
            ESP_ERROR_CHECK(strip4->set_pixel(strip4, j, ledData[((a_p+50)%200)*240+j*12+9],ledData[((a_p+50)%200)*240+j*12+10],ledData[((a_p+50)%200)*240+j*12+11]));
            
            
            // ESP_ERROR_CHECK(strip2->set_pixel(strip2, j, r, g/2, b/10));
            // ESP_ERROR_CHECK(strip3->set_pixel(strip3, j, r, g/2, b/10));
            // ESP_ERROR_CHECK(strip4->set_pixel(strip4, j, r, g/2, b/10));
            // ESP_ERROR_CHECK(strip1->set_pixel(strip1, j%10, i, i, i));
            // ESP_ERROR_CHECK(strip2->set_pixel(strip2, j, i/10, i/10, i/10));
        }

        ESP_ERROR_CHECK(strip1->refresh(strip1, 100));
        ESP_ERROR_CHECK(strip2->refresh(strip2, 100));
        ESP_ERROR_CHECK(strip3->refresh(strip3, 100));
        ESP_ERROR_CHECK(strip4->refresh(strip4, 100));


        // vTaskDelay(pdMS_TO_TICKS(10));
    }
    vTaskDelete(NULL);
}


static void decode_task(void *arg)
{
    vTaskDelay(pdMS_TO_TICKS(5000));
    char *work;
    int r;
    esp_rom_tjpgd_dec_t decoder;
    
    esp_err_t ret = ESP_OK;

    while (1) {   
        if(is_page_change)
        {
            is_page_change = 0;
            switch (page_num)
            {
            case 1: jd.fp = fopen("/littlefs/0001.jpeg","rb");
                break;
            case 2: jd.fp = fopen("/littlefs/0002.jpeg","rb");
                break;
            case 3: jd.fp = fopen("/littlefs/0003.jpeg","rb");
                break;
            case 4: jd.fp = fopen("/littlefs/0004.jpeg","rb");
                break;
            case 5: jd.fp = fopen("/littlefs/0005.jpeg","rb");
                break;
            case 6: jd.fp = fopen("/littlefs/0006.jpeg","rb");
                break;
            case 7: jd.fp = fopen("/littlefs/0007.jpeg","rb");
                break;
            case 8: jd.fp = fopen("/littlefs/0008.jpeg","rb");
                break;
            case 9: jd.fp = fopen("/littlefs/0009.jpeg","rb");
                break;
            case 10: jd.fp = fopen("/littlefs/0010.jpeg","rb");
                break;


            default: jd.fp = NULL;
                break;
            }
            // page++;
            // if(page>10)page=1;
            if(jd.fp)
            {
                size_t fileSize;
                fileSize = fread(image_data,sizeof(char),20000,jd.fp);
                esp_mqtt_client_publish(matt_client,mqtt_image_phone,image_data,fileSize,0,1);
                rewind(jd.fp);
                work = malloc(3500);
                    //Prepare and decode the jpeg.
                r = esp_rom_tjpgd_prepare(&decoder, infunc, work, 3500, (void *)&jd);
                if (r != JDR_OK) {
                    ESP_LOGE(TAG, "Image decoder: jd_prepare failed (%d)", r);
                    ret = ESP_ERR_NOT_SUPPORTED;
                    // goto err;
                }
                if(ret != ESP_ERR_NOT_SUPPORTED)r = esp_rom_tjpgd_decomp(&decoder, outfunc, 0);
                if (r != JDR_OK && r != JDR_FMT1) {
                    ESP_LOGE(TAG, "Image decoder: jd_decode failed (%d)", r);
                    ret = ESP_ERR_NOT_SUPPORTED;
                    // goto err;
                }
                free(work);
                fclose(jd.fp);
                if(ret != ESP_ERR_NOT_SUPPORTED)
                {
                    for(int i=0;i<200;i++)
                    {
                        for(int j=0;j<80;j++)
                        {
                            int32_t port = ((int32_t)(-sin(i/31.831)*j+80)*160+(int32_t)(cos(i/31.831)*j)+80);
                            ledData[i*240+j*3] =jd.outData[port*3]*(j+3)/300;
                            ledData[i*240+j*3+1] =jd.outData[port*3+1]*(j+3)/300;
                            ledData[i*240+j*3+2] =jd.outData[port*3+2]*(j+3)/300;
                        }
                        
                    }                    
                }
                else
                {
                    for(int32_t i=0;i<48000;i++)
                    {
                        ledData[i]=3;
                    }
                }  

            } 
            else
            {
                for(int32_t i=0;i<48000;i++)
                {
                    ledData[i]=3;
                }
            }           
        }

        vTaskDelay(pdMS_TO_TICKS(20));
    }
    vTaskDelete(NULL);
}


static void video_task(void *arg)
{
    while (1)
    {  

        if(is_video)
        {
            for(int i=0;i<(video_page-2);i++)
            {
                memcpy(ledData,ledDatas+48000*i,48000);
                if(is_video==0)break;
                vTaskDelay(pdMS_TO_TICKS(20));
                // ESP_LOGI(TAG, "imgarrays");
            }
            
        }

        vTaskDelay(pdMS_TO_TICKS(100));
    }
}

static void music_task(void *arg)
{
    while (1)
    {  

        if(is_video)
        {
            // char temp_cpr[8];
            // strncpy(temp_cpr,(char *)lr_wav_start,4);
            // if(strstr(temp_cpr , "RIFF"))
            // {
            //     printf("this is RIFF file\n");
            //     strncpy(temp_cpr,(char *)lr_wav_start+8,8);
            //     if(strstr(temp_cpr , "WAVEfmt "))
            //     {
            //         printf("this is wav file \n");

            //         printf("wav size = %02x, %02x, %02x, %02x\n",lr_wav_start[40],lr_wav_start[41],lr_wav_start[42],lr_wav_start[43]);

            //         printf("while_time = %d\n",lr_wav_start[40] + lr_wav_start[41]* (1<<8) + lr_wav_start[42]* (1<<16) + lr_wav_start[43] * (1<<24));

            //         printf("sample_rate = %d\n",lr_wav_start[24] + lr_wav_start[25]* (1<<8) + lr_wav_start[26]* (1<<16) + lr_wav_start[27] * (1<<24));

            //         size_t bytes_read, bytes_written = (4*1024);
            //         uint8_t* i2s_write_buff = (uint8_t*) calloc((16 * 1024), sizeof(char));
            //         // i2s_write(I2S_NUM, lr_wav_start+44, 1024, &bytes_read, 100);
            //         // for(int i=0;i<(8*1024);i=i+(4*1024))
            //         // {
            //         //     // int i2s_wr_len = i2s_data_scale(i2s_write_buff, (uint8_t*)(lr_wav_start+44+i), (4 * 1024));
            //         //     i2s_write(0, (uint8_t*)(lr_wav_start+44+i), 4*1024, &bytes_written, portMAX_DELAY);
            //         // }
            //         i2s_write(0, (uint8_t*)(lr_wav_start+44), lr_wav_end-lr_wav_start-44, &bytes_written, portMAX_DELAY);
            //         vTaskDelay(500/portTICK_RATE_MS);


            //         // int temp_current_time = 0;
            //         // bytes_read = 0;



            //     }
            // }
            size_t bytes_read, bytes_written = (4*1024);
            i2s_write(0, (uint8_t*)(music_data+44), music_Size-44, &bytes_written, portMAX_DELAY);
        }

        vTaskDelay(pdMS_TO_TICKS(10));
    }
}

static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
    ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%d", base, event_id);
    esp_mqtt_event_handle_t event = event_data;
    esp_mqtt_client_handle_t client = event->client;
    int msg_id;

    switch ((esp_mqtt_event_id_t)event_id) {
    case MQTT_EVENT_CONNECTED:
        ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
        
        msg_id = esp_mqtt_client_subscribe(client, mqtt_light, 1);
        ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);

        msg_id = esp_mqtt_client_subscribe(client, mqtt_open_btm, 1);
        ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);        

        msg_id = esp_mqtt_client_subscribe(client, mqtt_next_pic_btm, 1);
        ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);

        msg_id = esp_mqtt_client_subscribe(client, mqtt_last_pic_btm, 1);
        ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);

        msg_id = esp_mqtt_client_subscribe(client, mqtt_del_pic_btm, 1);
        ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);

        msg_id = esp_mqtt_client_subscribe(client, mqtt_pic_btm, 1);
        ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);

        msg_id = esp_mqtt_client_subscribe(client, mqtt_video_btm, 1);
        ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);

        msg_id = esp_mqtt_client_subscribe(client, mqtt_image_esp, 1);
        ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);

        break;
    case MQTT_EVENT_DISCONNECTED:
        ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
        break;

    case MQTT_EVENT_SUBSCRIBED:
        ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
        // msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0);
        // ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
        break;
    case MQTT_EVENT_UNSUBSCRIBED:
        ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
        break;
    case MQTT_EVENT_PUBLISHED:
        ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
        break;
    case MQTT_EVENT_DATA:
        ESP_LOGI(TAG, "MQTT_EVENT_DATA");
        printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
        printf("DATA=%.*s\r\n", event->data_len, event->data);
        if(strncmp(mqtt_light,event->topic,event->topic_len)==0)
        {
            if(strncmp("on",event->data,event->data_len)==0)
            {
                // gpio_set_level(4, 1);
                // is_light = 1;
                ESP_LOGI(TAG, "turn on light");
            }else if(strncmp("off",event->data,event->data_len)==0)
            {
                // gpio_set_level(4, 0);
                // is_light = 0;
                ESP_LOGI(TAG, "turn off light");
            }
            
        }
        else if(strncmp(mqtt_open_btm,event->topic,event->topic_len)==0)
        {
            if(is_open==0)
            {
                gpio_set_level(STEP_EN, 1);
                is_open = 1;
            }else
            {
                 gpio_set_level(STEP_EN, 0);
                is_open = 0;               
            }
            speed1 = 100;
        }       
        else if(strncmp(mqtt_next_pic_btm,event->topic,event->topic_len)==0)
        {
            is_page_change = 1;
            page_num++;
        }
        else if(strncmp(mqtt_last_pic_btm,event->topic,event->topic_len)==0)
        {
            is_page_change = 1;
            page_num--;
        }
        else if(strncmp(mqtt_image_esp,event->topic,event->topic_len)==0)
        {
            char file_path[200]={0};
            sprintf(file_path,"/littlefs/000%d.jpeg",page_num);
            FILE* f = fopen(file_path, "w");
            fwrite(event->data,sizeof(char),event->data_len,f);
            fclose(f);
            ESP_LOGI(TAG, "file_path=%d", event->data_len);
            is_page_change = 1;

        }
        else if(strncmp(mqtt_pic_btm,event->topic,event->topic_len)==0)
        {
            is_video = 0;
        }
        else if(strncmp(mqtt_video_btm,event->topic,event->topic_len)==0)
        {
            is_video = 1;
        }        
        break;
    case MQTT_EVENT_ERROR:
        ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
        break;
    default:
        ESP_LOGI(TAG, "Other event id:%d", event->event_id);
        break;
    }
}

static void mqtt_app_start(void)
{
    esp_mqtt_client_config_t mqtt_cfg = {
        .uri = "mqtt://plant.qinzr.top:1883",
        .username = "qinzr2",
        .password = "qzr@12345678",
    };
    matt_client = esp_mqtt_client_init(&mqtt_cfg);
    /* The last argument may be used to pass data to the event handler, in this example mqtt_event_handler */
    esp_mqtt_client_register_event(matt_client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
    esp_mqtt_client_start(matt_client);
}

static void setup_triangle_sine_waves(int bits)
{
    int *samples_data = malloc(((bits+8)/16)*SAMPLE_PER_CYCLE*4);
    unsigned int i, sample_val;
    double sin_float, triangle_float, triangle_step = (double) pow(2, bits) / SAMPLE_PER_CYCLE;
    size_t i2s_bytes_write = 0;

    printf("\r\nTest bits=%d free mem=%d, written data=%d\n", bits, esp_get_free_heap_size(), ((bits+8)/16)*SAMPLE_PER_CYCLE*4);

    triangle_float = -(pow(2, bits)/2 - 1);

    for(i = 0; i < SAMPLE_PER_CYCLE; i++) {
        sin_float = sin(i * 2 * PI / SAMPLE_PER_CYCLE);
        if(sin_float >= 0)
            triangle_float += triangle_step;
        else
            triangle_float -= triangle_step;

        sin_float *= (pow(2, bits)/2 - 1);

        if (bits == 16) {
            sample_val = 0;
            sample_val += (short)triangle_float;
            sample_val = sample_val << 16;
            sample_val += (short) sin_float;
            samples_data[i] = sample_val;
        } else if (bits == 24) { //1-bytes unused
            samples_data[i*2] = ((int) triangle_float) << 8;
            samples_data[i*2 + 1] = ((int) sin_float) << 8;
        } else {
            samples_data[i*2] = ((int) triangle_float);
            samples_data[i*2 + 1] = ((int) sin_float);
        }

    }
    ESP_LOGI(TAG, "set clock");
    i2s_set_clk(I2S_NUM, SAMPLE_RATE, bits, 2);
    //Using push
    // for(i = 0; i < SAMPLE_PER_CYCLE; i++) {
    //     if (bits == 16)
    //         i2s_push_sample(0, &samples_data[i], 100);
    //     else
    //         i2s_push_sample(0, &samples_data[i*2], 100);
    // }
    // or write
    ESP_LOGI(TAG, "write data");
    i2s_write(I2S_NUM, samples_data, ((bits+8)/16)*SAMPLE_PER_CYCLE*4, &i2s_bytes_write, 100);

    free(samples_data);
}


void app_main(void)
{
    //Initialize NVS
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
      ESP_ERROR_CHECK(nvs_flash_erase());
      ret = nvs_flash_init();
    } 

    //for 36Khz sample rates, we create 100Hz sine wave, every cycle need 36000/100 = 360 samples (4-bytes or 8-bytes each sample)
    //depend on bits_per_sample
    //using 6 buffers, we need 60-samples per buffer
    //if 2-channels, 16-bit each channel, total buffer is 360*4 = 1440 bytes
    //if 2-channels, 24/32-bit each channel, total buffer is 360*8 = 2880 bytes
    i2s_config_t i2s_config = {
        .mode = I2S_MODE_MASTER | I2S_MODE_TX,
        .sample_rate = SAMPLE_RATE,
        .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
        .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
        .communication_format = I2S_COMM_FORMAT_STAND_MSB,
        .dma_buf_count = 6,
        .dma_buf_len = 60,
        .use_apll = false,
        .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1                                //Interrupt level 1
    };
    i2s_pin_config_t pin_config = {
        .mck_io_num = I2S_PIN_NO_CHANGE,
        .bck_io_num = I2S_BCK_IO,
        .ws_io_num = I2S_WS_IO,
        .data_out_num = I2S_DO_IO,
        .data_in_num = I2S_DI_IO                                               //Not used
    };
    i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL);
    i2s_set_pin(I2S_NUM, &pin_config);

    sprintf(mqtt_light,"/%s/light","qinzr2"); 
    sprintf(mqtt_open_btm,"/%s/open_btn","qinzr2");  
    sprintf(mqtt_next_pic_btm,"/%s/next_pic_btn","qinzr2");  
    sprintf(mqtt_last_pic_btm,"/%s/last_pic_btn","qinzr2");  
    sprintf(mqtt_del_pic_btm,"/%s/del_pic_btn","qinzr2");  
    sprintf(mqtt_pic_btm,"/%s/pic_btn","qinzr2"); 
    sprintf(mqtt_video_btm,"/%s/video_btn","qinzr2"); 
    sprintf(mqtt_image_esp,"/%s/image_esp","qinzr2"); 
    sprintf(mqtt_image_phone,"/%s/image_phone","qinzr2"); 
    

    ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");
    my_wifi_init();
    // static httpd_handle_t server = NULL;
    // server = start_webserver();
    // mqtt_app_start();
    esp_vfs_littlefs_register(&littlefs_conf);
    music_data = malloc(2000000);
    ledDatas = malloc(200 * 80 * 300);
    ledData = malloc(200 * 80 * 3);
    FILE* f = fopen("/littlefs/imgarrays", "r");
    size_t fileSize;
    ESP_LOGI(TAG, "imgarrays=%d",video_page);
    while(!feof(f)) 
    {
        fileSize = fread(ledDatas+48000*video_page,sizeof(char),48000,f);
        video_page++;
        ESP_LOGI(TAG, "imgarrays=%d",video_page);
    } 
    fclose(f);

    f = fopen("/littlefs/music.wav", "r");

    music_Size = fread(music_data,sizeof(char),2000000,f);
    fclose(f);

    for(int32_t i=0;i<48000;i++)
    {
        ledData[i]=1;
        if(i<240*10&&i>240*9)ledData[i]=10;
        if(i%240>150&&i%240<160)ledData[i]=50;
    }

    strip1= led_strip_init(RMT_CHANNEL_0,GPIO_NUM_40,20);
    strip2= led_strip_init(RMT_CHANNEL_1,GPIO_NUM_39,20);
    strip3= led_strip_init(RMT_CHANNEL_2,GPIO_NUM_38,20);
    strip4= led_strip_init(RMT_CHANNEL_3,GPIO_NUM_41,20);
    step_gpio_init();
    gpio_set_level(STEP_EN, 1);
    gpio_set_level(STEP_DIR, 1);
    gpio_set_level(STEP_MS1, 0);
    gpio_set_level(STEP_MS2, 0);
    gpio_set_level(STEP_SPRD, 0);

    pwm_init();

    jd.outData = malloc(160 * 160 * 3);
    jd.outH = 160;
    jd.outW = 160;


    // Set duty to 10%
    ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, 250));
    // Update duty to apply the new value
    ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));
    example_tg_timer_init(TIMER_GROUP_1, TIMER_1, true, 10);

    ctrl_task_sem = xSemaphoreCreateBinary();
    xTaskCreatePinnedToCore(led_task, "led_task", 4096, NULL, 8, NULL, 1);
    xTaskCreatePinnedToCore(decode_task, "decode_task", 4096, NULL, 9, NULL, 0);
    xTaskCreatePinnedToCore(video_task, "video_task", 4096, NULL, 10, NULL, 0);
    xTaskCreatePinnedToCore(music_task, "music_task", 4096, NULL, 11, NULL, 0);
    while (1) 
    {

        // if(gpio_get_level(STEP_KEY)==0)
        // {
        //     speed1 = speed1*0.9;
        //     // vTaskDelay(pdMS_TO_TICKS(100));
        // }
        if(speed1>12)speed1 = speed1*0.9;
        speed = speed1;
        vTaskDelay(pdMS_TO_TICKS(100));

        // xSemaphoreGive(ctrl_task_sem);
    }

}
